# 参数：数据宽度data_width、数据深度data_depth、en默认1？
# 先只用ramb18e1，也就是width最大16，depth 1k？
# INIT_00到INIT_3F，每个256位,16进制

# yosys好像不支持reg的input output，只支持wire类型

from base.port_item import PortItem
from base.design import Design
from base.module import Module
from base.net import Net

from cells.ramb18e1 import RAMB18E1

class RomIP:
    

    def __init__(self,data_width:int=4, data_depth:int=2, module_name="rom_ip") -> None:
        self.ram_mode="TDP"
        self.port_clk:PortItem = None
        self.port_en:PortItem = None
        self.port_addr:PortItem = None
        self.port_dout:PortItem = None
        self.design:Design = None
        self.top_module: Module = None



        # 暂时只支持18位宽、18k容量
        assert(data_width in [1,2,4,8,16])
        assert(data_width*data_depth<=16*1024)

        self.data_width = data_width
        self.data_depth = data_depth
        self.module_name = module_name
        
        

        pass

    def get_inits(self):
        total_mem = self.data_depth*self.data_width
    def set_init_value(self,init_values:str):
        # 每个INIT_XX为256位，即64个16进制数字
        # 16进制,低位在右边
        
        pass
    
    # 根据设置的参数，生成module内容
    def gen_module(self):
        self.design = Design()
        self.top_module = Module(self.module_name)
        # 根据参数计算输入输出参数
        data_width_map = {
            1:1,
            2:2,
            4:4,
            8:9,
            16:18
        }
        ram_data_width = data_width_map[self.data_width]
        addr_width = get_addr_width(self.data_depth)
        self.top_module.add_port(PortItem(name="clk",parent=self.top_module))
        self.top_module.add_port(PortItem(width=addr_width,name="addr",parent=self.top_module))
        self.top_module.add_port(PortItem(type="out",width=ram_data_width,name="dout",parent=self.top_module))


        # 初始化ramb18e1
        ramb18e1_0 = RAMB18E1()
        self.top_module.add_cell(ramb18e1_0)
        # 添加net
        # clk
        self.top_module.add_net(Net("clk_wire",self.top_module.get_port("clk").get_pin(), ramb18e1_0.get_port("CLKARDCLK").get_pin()))
        # addr地址线，根据数据宽度计算，如数据宽度是8，地址线是11位，连接ramb18e1的ADDRARDADDR高11位
        addr_move_map = {
            1:0,
            2:1,
            4:2,
            8:3,
            16:4
        }
        addr_move_count = addr_move_map[self.data_width]
        for i in range(addr_width):
            self.top_module.add_net(Net("addr_"+str(i),self.top_module.get_port("addr").get_pin_by_index(i), ramb18e1_0.get_port("ADDRARDADDR").get_pin_by_index(i+addr_move_count)))
        for i in range(self.data_width):
            self.top_module.add_net(Net("dout_"+str(i), self.top_module.get_port("dout").get_pin_by_index(i), ramb18e1_0.get_port("DOADO").get_pin_by_index(i)))
        pass

    # 根据当前的cell，生成pin id
    def gen_pin_id(self):
        index = 1
        for port in self.top_module.get_all_ports():
            for pin in port.get_all_pins():
                pin.set_id(index)
                index +=1
    
        
    # def write_verilog(self) -> str:
    #     sb = ""
    #     sb += "module {}(\n".format(self.module_name)
    #     sb += "\t{} {} {},\n".format(self.port_clk.type,self.port_clk.get_width_str(),self.port_clk.name)
    #     sb += "\t{} {} {},\n".format(self.port_en.type,self.port_en.get_width_str(),self.port_en.name)
    #     sb += "\t{} {} {},\n".format(self.port_addr.type,self.port_addr.get_width_str(),self.port_addr.name)
    #     sb += "\t{} {} {}\n);\n".format(self.port_dout.type,self.port_dout.get_width_str(),self.port_dout.name)

    #     # ramb18e1
    #     sb += "\tRAMB18E1 #("
    #     sb += "\t\t.RAM_MODE(\"{}\"),".format(self.ram_mode)
    #     sb += "\t\t.READ_WIDTH_A({}),".format(self.data_depth)


    #     sb+= "\nendmodule"
    #     return sb

import math

def get_addr_width(x:int):
    if x < 1:
        return 0
    return math.ceil(math.log2(x))


if __name__ == "__main__":
    rom_ip_inst = RomIP()
    rom_ip_inst.gen_module()
    pass
    # rom_ip_inst.port_clk=PortItem(name="clk")
    # rom_ip_inst.port_addr=PortItem(name="addr",width=4)
    # rom_ip_inst.port_en=PortItem(name="en")
    # rom_ip_inst.port_dout=PortItem(name="dout",width=4)

    # s = rom_ip_inst.write_verilog()
    # with open("out.v",'w') as f:
    #     f.write(s)